package de.sisoft.gcjack.communication;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;

import android.util.Log;
import de.sisoft.gcjack.exception.DefaultConnectionException;
import de.sisoft.gcjack.exception.NoResultFoundException;
import de.sisoft.gcjack.exception.UserAlreadyVotedException;
import de.sisoft.gcjack.model.GeoCache;
import de.sisoft.gcjack.model.User;

public class ConnectionManager {

	private final String		URL_GET_GEOCACHE_DETAILS	= "http://www.gcjack.com/connect/get_geocache_details.php";
	private final String		URL_GET_VOTING_DETAILS		= "http://www.gcjack.com/connect/get_voting_details.php";
	private final String		URL_PUT_VOTINGS				= "http://www.gcjack.com/connect/put_voting.php";

	// TODO: get later from user to connect to gc
	private String				authUser					= "admin";
	private String				authPasswd					= "#siegesmund#";

	private JSONParser			jsonParser					= new JSONParser();
	private ResponseBuilder		responseBuilder				= new ResponseBuilder();
	private RequestBuilder		requestBuilder				= new RequestBuilder();
	private DefaultHttpClient	httpClient					= new DefaultHttpClient();
	private boolean				authRequired				= true;

	private HttpGet				httpGet;
	private HttpPost			httpPost;

	public GeoCache updateGeoCache(GeoCache geocache) throws NoResultFoundException, DefaultConnectionException, UserAlreadyVotedException {
		List<NameValuePair> params = requestBuilder.buildGeocacheDetailsRequest(geocache);
		HttpResponse response = null;
		// geocache details
		try {
			httpPost = buildPostRequest(URL_GET_GEOCACHE_DETAILS, params);
			response = httpClient.execute(httpPost);
		} catch (ClientProtocolException e) {
			throw new DefaultConnectionException(e.getLocalizedMessage());
		} catch (IOException e) {
			throw new DefaultConnectionException(e.getLocalizedMessage());
		}
		try {
			geocache = responseBuilder.buildGeoCacheDetailsFromJson(jsonParser.parse(response), geocache);
		} catch (JSONException je) {
			throw new DefaultConnectionException(je.getLocalizedMessage());
		}
		// geocache rating
		try {
			httpPost = buildPostRequest(URL_GET_VOTING_DETAILS, params);
			response = httpClient.execute(httpPost);
		} catch (ClientProtocolException e) {
			throw new DefaultConnectionException(e.getLocalizedMessage());
		} catch (IOException e) {
			throw new DefaultConnectionException(e.getLocalizedMessage());
		}
		try {
			geocache = responseBuilder.buildGeoCacheVotingsFromJson(jsonParser.parse(response), geocache);
		} catch (JSONException je) {
			throw new DefaultConnectionException(je.getMessage());
		}
		return geocache;
	}

	public GeoCache voteGeoCache(GeoCache geocache, User user) throws NoResultFoundException,
			DefaultConnectionException, UserAlreadyVotedException {
		List<NameValuePair> params = requestBuilder.buildGeocacheVotingsRequest(geocache, user);
		HttpResponse response = null;
		// geocache details
		try {
			httpPost = buildPostRequest(URL_PUT_VOTINGS, params);
			response = httpClient.execute(httpPost);
		} catch (ClientProtocolException e) {
			throw new DefaultConnectionException(e.getLocalizedMessage());
		} catch (IOException e) {
			throw new DefaultConnectionException(e.getLocalizedMessage());
		}
		try {
			geocache = responseBuilder.buildGeoCacheVotingsFromJson(jsonParser.parse(response), geocache);
		} catch (JSONException je) {
			throw new DefaultConnectionException(je.getLocalizedMessage());
		}
		return geocache;
	}

	public User updateUser(User user) {

		return responseBuilder.buildUser(null);
	}

	private HttpGet buildGetRequest(ConnectionMode mode, String uri, List<NameValuePair> params) {

		String paramString = URLEncodedUtils.format(params, Constants.UTF_ENCODING);
		String url = uri;
		url += "?" + paramString;
		HttpGet httpGet = new HttpGet(url);
		if (authRequired) {
			httpGet.addHeader(BasicScheme.authenticate(new UsernamePasswordCredentials(authUser, authPasswd), "UTF-8",
					false));
		}
		Log.w("GCJack Request: ", httpGet.toString());
		return httpGet;
	}

	private HttpPost buildPostRequest(String uri, List<NameValuePair> params) throws UnsupportedEncodingException {

		String paramString = URLEncodedUtils.format(params, Constants.UTF_ENCODING);
		String url = uri;
		url += "?" + paramString;

		HttpPost httpPost = new HttpPost(url);
		if (authRequired) {
			httpPost.addHeader(BasicScheme.authenticate(new UsernamePasswordCredentials(authUser, authPasswd),
					Constants.UTF_ENCODING, false));
		}
		httpPost.setEntity(new UrlEncodedFormEntity(params));
		Log.i("GCJack Request: ", httpPost.toString());
		return httpPost;
	}

	public DefaultHttpClient getHttpClient() {
		return httpClient;
	}

	public void setHttpClient(DefaultHttpClient httpClient) {
		this.httpClient = httpClient;
	}

	public HttpGet getHttpGet() {
		return httpGet;
	}

	public void setHttpGet(HttpGet httpGet) {
		this.httpGet = httpGet;
	}

	public HttpPost getHttpPost() {
		return httpPost;
	}

	public void setHttpPost(HttpPost httpPost) {
		this.httpPost = httpPost;
	}

}
